//! 缓存管理模块
//! 
//! 这个模块负责Redis缓存的管理和操作，包括：
//! - Redis连接池管理
//! - 缓存操作（设置、获取、删除）
//! - 缓存键管理
//! - 缓存策略实现

use deadpool_redis::{Pool, Runtime, Config};
use redis::AsyncCommands;
use uuid::Uuid;
use serde::{Serialize, Deserialize};

use crate::{
    config::RedisConfig,
    models::User,
    errors::{AppError, AppResult},
};

/// 缓存管理器
/// 
/// 负责管理Redis连接池和提供缓存操作方法
#[derive(Clone)]
pub struct CacheManager {
    /// Redis连接池
    pool: Pool,
    /// 缓存配置
    config: RedisConfig,
}

impl CacheManager {
    /// 创建新的缓存管理器
    /// 
    /// # 参数
    /// - `config`: Redis配置
    /// 
    /// # 返回值
    /// - `Result<Self, AppError>`: 创建成功返回管理器，失败返回错误
    pub async fn new(config: &RedisConfig) -> AppResult<Self> {
        tracing::info!("🔗 初始化Redis连接池...");

        let pool_config = config.redis_pool_config();
        let pool = pool_config.create_pool(Some(Runtime::Tokio1))
            .map_err(|e| AppError::Redis(redis::RedisError::from((redis::ErrorKind::IoError, "连接池创建失败"))))?;

        // 测试连接
        let mut conn = pool.get().await
            .map_err(|e| AppError::Redis(redis::RedisError::from((redis::ErrorKind::IoError, "获取连接失败"))))?;
        
        conn.set::<&str, &str, ()>("test", "connection").await
            .map_err(|e| AppError::Redis(e))?;
        conn.del::<&str, ()>("test").await
            .map_err(|e| AppError::Redis(e))?;

        tracing::info!("✅ Redis连接池初始化完成");
        Ok(Self {
            pool,
            config: config.clone(),
        })
    }

    /// 健康检查
    /// 
    /// 检查Redis连接是否正常
    /// 
    /// # 返回值
    /// - `Result<(), AppError>`: 健康检查成功返回Ok，失败返回错误
    pub async fn health_check(&self) -> AppResult<()> {
        let mut conn = self.pool.get().await
            .map_err(|e| AppError::Redis(redis::RedisError::from((redis::ErrorKind::IoError, "获取连接失败"))))?;
        
        redis::cmd("PING")
            .query_async::<_, String>(&mut *conn)
            .await
            .map_err(AppError::Redis)?;

        Ok(())
    }

    /// 获取连接池信息
    /// 
    /// # 返回值
    /// - `(usize, usize)`: (活跃连接数, 空闲连接数)
    pub fn get_pool_info(&self) -> (usize, usize) {
        (self.pool.status().size, self.pool.status().available)
    }

    /// 关闭缓存连接池
    /// 
    /// 优雅地关闭所有Redis连接
    pub async fn close(&self) {
        // deadpool-redis 会自动管理连接池的关闭
        tracing::info!("🔒 Redis连接池已关闭");
    }
}

/// 通用缓存操作
impl CacheManager {
    /// 设置缓存值
    /// 
    /// # 参数
    /// - `key`: 缓存键
    /// - `value`: 缓存值（可序列化的类型）
    /// - `ttl`: 过期时间（秒），None表示不过期
    /// 
    /// # 返回值
    /// - `Result<(), AppError>`: 设置成功返回Ok，失败返回错误
    pub async fn set<T>(&self, key: &str, value: &T, ttl: Option<u64>) -> AppResult<()>
    where
        T: Serialize,
    {
        let serialized = serde_json::to_string(value)
            .map_err(AppError::Serialization)?;

        let mut conn = self.pool.get().await
            .map_err(|e| AppError::Redis(redis::RedisError::from((redis::ErrorKind::IoError, "获取连接失败"))))?;

        match ttl {
            Some(ttl) => {
                conn.set_ex::<&str, &str, ()>(key, &serialized, ttl).await
                    .map_err(AppError::Redis)?;
            }
            None => {
                conn.set::<&str, &str, ()>(key, &serialized).await
                    .map_err(AppError::Redis)?;
            }
        }

        tracing::debug!("✅ 缓存设置成功: {}", key);
        Ok(())
    }

    /// 获取缓存值
    /// 
    /// # 参数
    /// - `key`: 缓存键
    /// 
    /// # 返回值
    /// - `Result<Option<T>, AppError>`: 找到值返回Some，未找到返回None，失败返回错误
    pub async fn get<T>(&self, key: &str) -> AppResult<Option<T>>
    where
        T: for<'de> Deserialize<'de>,
    {
        let mut conn = self.pool.get().await
            .map_err(|e| AppError::Redis(redis::RedisError::from((redis::ErrorKind::IoError, "获取连接失败"))))?;

        let value: Option<String> = conn.get(key).await
            .map_err(AppError::Redis)?;

        match value {
            Some(data) => {
                let deserialized: T = serde_json::from_str(&data)
                    .map_err(AppError::Serialization)?;
                
                tracing::debug!("✅ 缓存命中: {}", key);
                Ok(Some(deserialized))
            }
            None => {
                tracing::debug!("❌ 缓存未命中: {}", key);
                Ok(None)
            }
        }
    }

    /// 删除缓存值
    /// 
    /// # 参数
    /// - `key`: 缓存键
    /// 
    /// # 返回值
    /// - `Result<bool, AppError>`: 删除成功返回true，键不存在返回false，失败返回错误
    pub async fn del(&self, key: &str) -> AppResult<bool> {
        let mut conn = self.pool.get().await
            .map_err(|e| AppError::Redis(redis::RedisError::from((redis::ErrorKind::IoError, "获取连接失败"))))?;

        let result: i32 = conn.del::<&str, i32>(key).await
            .map_err(AppError::Redis)?;

        tracing::debug!("✅ 缓存删除成功: {}", key);
        Ok(result > 0)
    }

    /// 批量删除缓存值（按模式匹配）
    /// 
    /// # 参数
    /// - `pattern`: 键的模式（支持通配符）
    /// 
    /// # 返回值
    /// - `Result<usize, AppError>`: 删除成功返回删除的键数量，失败返回错误
    pub async fn del_pattern(&self, pattern: &str) -> AppResult<usize> {
        let mut conn = self.pool.get().await
            .map_err(|e| AppError::Redis(redis::RedisError::from((redis::ErrorKind::IoError, "获取连接失败"))))?;

        let keys: Vec<String> = conn.keys(pattern).await
            .map_err(AppError::Redis)?;

        if keys.is_empty() {
            return Ok(0);
        }

        let count: i32 = conn.del::<Vec<String>, i32>(keys).await
            .map_err(AppError::Redis)?;

        tracing::debug!("✅ 批量删除缓存成功: {} 个键", count);
        Ok(count as usize)
    }

    /// 检查键是否存在
    /// 
    /// # 参数
    /// - `key`: 缓存键
    /// 
    /// # 返回值
    /// - `Result<bool, AppError>`: 存在返回true，不存在返回false，失败返回错误
    pub async fn exists(&self, key: &str) -> AppResult<bool> {
        let mut conn = self.pool.get().await
            .map_err(|e| AppError::Redis(redis::RedisError::from((redis::ErrorKind::IoError, "获取连接失败"))))?;

        let exists: bool = conn.exists(key).await
            .map_err(AppError::Redis)?;

        Ok(exists)
    }

    /// 设置过期时间
    /// 
    /// # 参数
    /// - `key`: 缓存键
    /// - `ttl`: 过期时间（秒）
    /// 
    /// # 返回值
    /// - `Result<bool, AppError>`: 设置成功返回true，键不存在返回false，失败返回错误
    pub async fn expire(&self, key: &str, ttl: u64) -> AppResult<bool> {
        let mut conn = self.pool.get().await
            .map_err(|e| AppError::Redis(redis::RedisError::from((redis::ErrorKind::IoError, "获取连接失败"))))?;

        let result: bool = conn.expire::<&str, bool>(key, ttl as i64).await
            .map_err(AppError::Redis)?;

        Ok(result)
    }

    /// 获取剩余过期时间
    /// 
    /// # 参数
    /// - `key`: 缓存键
    /// 
    /// # 返回值
    /// - `Result<i64, AppError>`: 剩余秒数，-1表示没有过期时间，-2表示键不存在，失败返回错误
    pub async fn ttl(&self, key: &str) -> AppResult<i64> {
        let mut conn = self.pool.get().await
            .map_err(|e| AppError::Redis(redis::RedisError::from((redis::ErrorKind::IoError, "获取连接失败"))))?;

        let ttl: i64 = conn.ttl(key).await
            .map_err(AppError::Redis)?;

        Ok(ttl)
    }

    /// 增加计数器
    /// 
    /// # 参数
    /// - `key`: 缓存键
    /// - `increment`: 增量值，默认为1
    /// 
    /// # 返回值
    /// - `Result<i64, AppError>`: 增加后的值，失败返回错误
    pub async fn incr(&self, key: &str, increment: Option<i64>) -> AppResult<i64> {
        let mut conn = self.pool.get().await
            .map_err(|e| AppError::Redis(redis::RedisError::from((redis::ErrorKind::IoError, "获取连接失败"))))?;

        let result = match increment {
            Some(inc) => {
                conn.incr::<&str, i64, i64>(key, inc).await
                    .map_err(AppError::Redis)?
            }
            None => {
                conn.incr::<&str, i64, i64>(key, 1).await
                    .map_err(AppError::Redis)?
            }
        };

        Ok(result)
    }
}

/// 用户缓存操作
impl CacheManager {
    /// 缓存用户信息
    /// 
    /// # 参数
    /// - `user`: 用户信息
    /// - `ttl`: 过期时间（秒），None表示使用默认值
    /// 
    /// # 返回值
    /// - `Result<(), AppError>`: 缓存成功返回Ok，失败返回错误
    pub async fn cache_user(&self, user: &User, ttl: Option<u64>) -> AppResult<()> {
        let ttl = ttl.unwrap_or(3600); // 默认1小时

        // 缓存用户基本信息
        self.set(&format!("user:{}", user.id), user, Some(ttl)).await?;

        // 缓存用户索引（邮箱和用户名）
        self.set(&format!("user:email:{}", user.email), &user.id, Some(ttl)).await?;
        self.set(&format!("user:username:{}", user.username), &user.id, Some(ttl)).await?;

        tracing::info!("✅ 用户缓存成功: {}", user.username);
        Ok(())
    }

    /// 获取缓存的用户信息
    /// 
    /// # 参数
    /// - `user_id`: 用户ID
    /// 
    /// # 返回值
    /// - `Result<Option<User>, AppError>`: 找到用户返回Some，未找到返回None，失败返回错误
    pub async fn get_cached_user(&self, user_id: Uuid) -> AppResult<Option<User>> {
        self.get(&format!("user:{}", user_id)).await
    }

    /// 根据邮箱获取缓存的用户
    /// 
    /// # 参数
    /// - `email`: 用户邮箱
    /// 
    /// # 返回值
    /// - `Result<Option<User>, AppError>`: 找到用户返回Some，未找到返回None，失败返回错误
    pub async fn get_cached_user_by_email(&self, email: &str) -> AppResult<Option<User>> {
        // 先获取用户ID
        let user_id: Option<Uuid> = self.get(&format!("user:email:{}", email)).await?;

        match user_id {
            Some(id) => self.get_cached_user(id).await,
            None => Ok(None),
        }
    }

    /// 根据用户名获取缓存的用户
    /// 
    /// # 参数
    /// - `username`: 用户名
    /// 
    /// # 返回值
    /// - `Result<Option<User>, AppError>`: 找到用户返回Some，未找到返回None，失败返回错误
    pub async fn get_cached_user_by_username(&self, username: &str) -> AppResult<Option<User>> {
        // 先获取用户ID
        let user_id: Option<Uuid> = self.get(&format!("user:username:{}", username)).await?;

        match user_id {
            Some(id) => self.get_cached_user(id).await,
            None => Ok(None),
        }
    }

    /// 删除缓存的用户信息
    /// 
    /// # 参数
    /// - `user_id`: 用户ID
    /// 
    /// # 返回值
    /// - `Result<(), AppError>`: 删除成功返回Ok，失败返回错误
    pub async fn delete_cached_user(&self, user_id: Uuid) -> AppResult<()> {
        // 先获取用户信息以删除索引
        if let Some(user) = self.get_cached_user(user_id).await? {
            self.del(&format!("user:email:{}", user.email)).await?;
            self.del(&format!("user:username:{}", user.username)).await?;
        }

        // 删除用户基本信息
        self.del(&format!("user:{}", user_id)).await?;

        tracing::info!("✅ 用户缓存删除成功: {}", user_id);
        Ok(())
    }

    /// 更新缓存的用户信息
    /// 
    /// # 参数
    /// - `user`: 更新后的用户信息
    /// - `ttl`: 过期时间（秒），None表示使用默认值
    /// 
    /// # 返回值
    /// - `Result<(), AppError>`: 更新成功返回Ok，失败返回错误
    pub async fn update_cached_user(&self, user: &User, ttl: Option<u64>) -> AppResult<()> {
        // 删除旧缓存
        self.delete_cached_user(user.id).await?;

        // 设置新缓存
        self.cache_user(user, ttl).await
    }
}

/// 会话缓存操作
impl CacheManager {
    /// 缓存用户会话
    /// 
    /// # 参数
    /// - `session_id`: 会话ID
    /// - `user_id`: 用户ID
    /// - `ttl`: 过期时间（秒）
    /// 
    /// # 返回值
    /// - `Result<(), AppError>`: 缓存成功返回Ok，失败返回错误
    pub async fn cache_session(&self, session_id: &str, user_id: Uuid, ttl: u64) -> AppResult<()> {
        self.set(&format!("session:{}", session_id), &user_id, Some(ttl)).await
    }

    /// 获取会话对应的用户ID
    /// 
    /// # 参数
    /// - `session_id`: 会话ID
    /// 
    /// # 返回值
    /// - `Result<Option<Uuid>, AppError>`: 找到返回用户ID，未找到返回None，失败返回错误
    pub async fn get_session_user(&self, session_id: &str) -> AppResult<Option<Uuid>> {
        self.get(&format!("session:{}", session_id)).await
    }

    /// 删除会话
    /// 
    /// # 参数
    /// - `session_id`: 会话ID
    /// 
    /// # 返回值
    /// - `Result<bool, AppError>`: 删除成功返回true，会话不存在返回false，失败返回错误
    pub async fn delete_session(&self, session_id: &str) -> AppResult<bool> {
        self.del(&format!("session:{}", session_id)).await
    }
}

/// 实现配置的Redis池配置方法
impl RedisConfig {
    /// 获取Redis连接池配置
    /// 
    /// # 返回值
    /// - `deadpool_redis::Config`: 配置好的连接池配置
    pub fn redis_pool_config(&self) -> Config {
        Config::from_url(&self.url)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::models::{UserStatus, UserRole};
    use chrono::Utc;

    fn create_test_user() -> User {
        User {
            id: Uuid::new_v4(),
            username: "test_user".to_string(),
            email: "test@example.com".to_string(),
            password_hash: "hashed_password".to_string(),
            full_name: Some("Test User".to_string()),
            avatar_url: None,
            status: UserStatus::Active,
            role: UserRole::User,
            created_at: Utc::now(),
            updated_at: Utc::now(),
            last_login_at: None,
        }
    }

    #[tokio::test]
    async fn test_cache_operations() {
        // 注意：这个测试需要Redis服务器运行
        // 在实际测试中，应该使用测试专用的Redis实例
        let config = RedisConfig::default();
        let cache = CacheManager::new(&config).await;

        // 如果Redis不可用，跳过测试
        let cache = match cache {
            Ok(cache) => cache,
            Err(_) => {
                println!("跳过Redis测试：Redis服务器不可用");
                return;
            }
        };

        let test_data = "test_value";
        let key = "test_key";

        // 测试设置和获取
        cache.set(key, &test_data, Some(60)).await.unwrap();
        let retrieved: Option<String> = cache.get(key).await.unwrap();
        assert_eq!(retrieved, Some(test_data.to_string()));

        // 测试删除
        cache.del(key).await.unwrap();
        let deleted: Option<String> = cache.get(key).await.unwrap();
        assert_eq!(deleted, None);
    }

    #[tokio::test]
    async fn test_user_caching() {
        let config = RedisConfig::default();
        let cache = CacheManager::new(&config).await;

        let cache = match cache {
            Ok(cache) => cache,
            Err(_) => {
                println!("跳过用户缓存测试：Redis服务器不可用");
                return;
            }
        };

        let user = create_test_user();

        // 测试用户缓存
        cache.cache_user(&user, Some(60)).await.unwrap();

        // 测试通过ID获取
        let cached_user = cache.get_cached_user(user.id).await.unwrap();
        assert!(cached_user.is_some());
        assert_eq!(cached_user.unwrap().username, user.username);

        // 测试通过邮箱获取
        let cached_user = cache.get_cached_user_by_email(&user.email).await.unwrap();
        assert!(cached_user.is_some());
        assert_eq!(cached_user.unwrap().username, user.username);

        // 测试通过用户名获取
        let cached_user = cache.get_cached_user_by_username(&user.username).await.unwrap();
        assert!(cached_user.is_some());
        assert_eq!(cached_user.unwrap().username, user.username);

        // 测试删除用户缓存
        cache.delete_cached_user(user.id).await.unwrap();
        let deleted_user = cache.get_cached_user(user.id).await.unwrap();
        assert!(deleted_user.is_none());
    }
}
